package com.listeningframework.boot.codegen.lang;

import com.listeningframework.boot.codegen.exception.BusinessException;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 
 * @description Java Reflect Utils 
 *  
 * @author listening
 * @version $Id: ListeningReflectUtils.java, v 0.1 2015年6月11日 下午10:36:56 listening Exp $
 */
public class ReflectUtils {

    /**
     * Java动态添加library path
     *
     * @throws IOException
     */
    public static final void addLibraryPath(String path) {
        try {
            String libraryPath = System.getProperty("java.library.path");
            System.setProperty("java.library.path", libraryPath + ";" + path);
            Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
            fieldSysPath.setAccessible(true);
            fieldSysPath.set(null, null);
        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
            throw new RuntimeException("add library path fail");
        }
    }

    /**
     * Java动态添加library path
     *
     * @throws IOException
     */
    public static final void addLibrarySigarPath() {
        String path = ReflectUtils.class.getResource("/libsigar").getPath();
        addLibraryPath(path);
    }

    /**
     * 获取泛型参数Class
     * 
     * @param cls
     * @return Class<?>
     */
    public static final Class<?> getGenericClass(Class<?> cls) {
        if (cls == null || cls.getGenericSuperclass() == null) {
            return null;
        }
        Type type = cls.getGenericSuperclass();
        if (!(type instanceof ParameterizedType)) {
            return null;
        }
        ParameterizedType parameterType = (ParameterizedType) type;
        return (Class<?>) parameterType.getActualTypeArguments()[0];
    }

    /**
     * 泛型参数名称
     * 
     * @param cls
     * @return Stirng
     */
    public static final String getGenericClassName(Class<?> cls) {
        Class<?> genericClass = getGenericClass(cls);
        return genericClass == null ? null : genericClass.getSimpleName();
    }

    /**
     * 类型是否一致
     * 
     * @param sourceClz
     * @param compareClz
     * @return boolean
     */
    public static final boolean isType(Class<?> sourceClz, Class<?> compareClz) {
        if (sourceClz == null || compareClz == null) {
            return false;
        }
        return StringUtils.equals(sourceClz.getName(), compareClz.getName());
    }

    /**
     * 根据Class实例一个对象
     * 
     * @param clz
     * @return
     * @throws BusinessException
     */
    public static final <T> T newInstance(Class<T> clz) throws BusinessException {
        try {
            return clz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new BusinessException("Construct Clz Fail", e);
        }
    }

    /**
     * 根据Class实例一个对象
     * 
     * @param clz
     * @return
     * @throws BusinessException
     */
    public static final <T> T safenewInstance(Class<T> clz) {
        try {
            return clz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException("Construct Clz Fail", e);
        }
    }

    /**
     * Find Annotation Fields
     * 
     * @param clz
     * @param annotationClass
     * @return List<Field>
     */
    public static final List<Field> findAnnotationFields(Class<?> clz, Class<? extends Annotation> annotationClass) {
        List<Field> fieldList = new ArrayList<>();
        Field[] fieldArray = clz.getDeclaredFields();
        if (fieldArray == null || fieldArray.length == 0) {
            return fieldList;
        }
        for (Field field : fieldArray) {
            if (field.isAnnotationPresent(annotationClass)) {
                fieldList.add(field);
            }
        }
        return fieldList;
    }

    /**
     * 获取Class的包名
     * 
     * @param clz
     * @return String
     */
    public static final String getClassPackage(Class<?> clz) {
        String name = clz.getName();
        return name.substring(0, name.lastIndexOf("."));
    }

    /**
     * 获取父类已经声明的属性名称列表
     * 
     * @param clz - 要检测的类
     * @return Set<String>
     */
    public static final Set<String> getSuperFields(Class<?> clz) {
        Set<String> result = new HashSet<>();
        getSuperFieldsImpl(clz, result);
        return result;
    }

    private static final void getSuperFieldsImpl(Class<?> clz, Set<String> result) {
        Class<?> currentClz = clz.getSuperclass();
        Field[] fields = currentClz.getDeclaredFields();
        if (fields == null || fields.length < 1) {
            return;
        }
        for (Field field : fields) {
            result.add(field.getName());
        }
        getSuperFieldsImpl(currentClz, result);
    }

}
